<template>
	<div class="min-h-screen bg-gradient-to-br from-blue-50 to-purple-50 py-8">
		<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
			<!-- Header -->
			<div class="text-center mb-8">
				<h1 class="text-3xl font-bold text-gray-900 mb-4">
					<span class="text-gradient">API 测试工具</span>
				</h1>
				<p class="text-lg text-gray-600">支持快速发送 GET/POST 等请求，可自定义请求头与 body，并查看响应状态、响应头与响应体</p>
			</div>

			<div class="bg-white rounded-xl shadow-lg p-6">
				<!-- Form -->
				<div class="grid grid-cols-1 md:grid-cols-4 gap-3 mb-4">
					<div class="md:col-span-1">
						<label class="block text-sm font-medium text-gray-700 mb-2">Method</label>
						<select v-model="method" class="form-select w-full">
							<option>GET</option>
							<option>POST</option>
							<option>PUT</option>
							<option>PATCH</option>
							<option>DELETE</option>
						</select>
					</div>

					<div class="md:col-span-3">
						<label class="block text-sm font-medium text-gray-700 mb-2">URL</label>
						<input v-model="url" type="text" class="input-field w-full" placeholder="https://api.example.com/path" />
					</div>
				</div>

				<div class="mb-4">
					<label class="block text-sm font-medium text-gray-700 mb-2">请求头（每行一项，格式: Key: Value）</label>
					<textarea v-model="headersText" class="textarea-field h-24" placeholder="Authorization: Bearer TOKEN\nAccept: application/json"></textarea>
				</div>

				<div class="mb-4">
					<div class="flex items-center justify-between mb-2">
						<label class="block text-sm font-medium text-gray-700">请求体（raw）</label>
						<div class="text-sm text-gray-500">Content-Type: <select v-model="contentType" class="form-select ml-2 inline-block w-auto">
							<option value="application/json">application/json</option>
							<option value="text/plain">text/plain</option>
							<option value="application/x-www-form-urlencoded">application/x-www-form-urlencoded</option>
							<option value="multipart/form-data">multipart/form-data</option>
						</select></div>
					</div>
					<textarea v-model="bodyText" class="textarea-field h-40" placeholder='例如 JSON: {"name":"张三"}'></textarea>
				</div>

				<div class="mb-4 flex items-center space-x-3">
					<label class="inline-flex items-center space-x-2 text-sm text-gray-700">
						<span>超时 (秒)</span>
						<input v-model.number="timeoutSec" type="number" min="1" class="input-field w-24 ml-2" />
					</label>

					<button @click="sendRequest" :disabled="sending" class="primary-button">
						{{ sending ? '发送中...' : '发送请求' }}
					</button>
					<button @click="clearAll" class="secondary-button">清空</button>
					<button @click="loadSample" class="secondary-button">加载示例</button>
				</div>

				<div v-if="errorMessage" class="mb-4 p-3 bg-red-50 border border-red-200 rounded-lg">
					<p class="text-red-600 text-sm">{{ errorMessage }}</p>
				</div>

				<!-- Result -->
				<div v-if="hasResponse" class="mt-4">
					<div class="mb-3 flex flex-wrap items-center gap-3">
						<div class="px-3 py-2 bg-gray-100 rounded">Status: <strong>{{ responseStatus }}</strong></div>
						<div class="px-3 py-2 bg-gray-100 rounded">Time: <strong>{{ elapsed }} ms</strong></div>
						<div class="px-3 py-2 bg-gray-100 rounded">Size: <strong>{{ responseSize }}</strong></div>
						<button @click="copyResponse" class="secondary-button">复制响应</button>
						<button @click="downloadResponse" class="secondary-button">下载响应</button>
					</div>

					<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
						<div class="bg-gray-50 border rounded p-3 overflow-auto">
							<h3 class="text-sm font-medium text-gray-800 mb-2">响应头</h3>
							<pre class="text-xs text-gray-700">{{ formattedResponseHeaders }}</pre>
						</div>

						<div class="bg-gray-50 border rounded p-3 overflow-auto">
							<h3 class="text-sm font-medium text-gray-800 mb-2">响应体</h3>
							<div v-if="isJsonResponse">
								<pre class="text-xs text-gray-700">{{ prettyJson }}</pre>
							</div>
							<div v-else>
								<pre class="text-xs text-gray-700">{{ responseText }}</pre>
							</div>
						</div>
					</div>
				</div>

				<!-- Request preview -->
				<div class="mt-6 bg-white rounded-lg p-4 border">
					<h3 class="text-sm font-medium text-gray-800 mb-2">请求预览</h3>
					<pre class="text-xs text-gray-700">{{ requestPreview }}</pre>
				</div>
			</div>
		</div>
	</div>
</template>

<script setup>
import { ref, computed } from 'vue'


const method = ref('GET')
const url = ref('')
const headersText = ref('')
const bodyText = ref('')
const contentType = ref('application/json')
const timeoutSec = ref(10)

const sending = ref(false)
const errorMessage = ref('')

const hasResponse = ref(false)
const responseStatus = ref('')
const responseHeaders = ref({})
const responseText = ref('')
const responseSize = ref('0 B')
const elapsed = ref(0)

// helpers
const parseHeadersText = (text) => {
	const lines = text.split(/\r?\n/).filter(Boolean)
	const hdrs = {}
	for (const line of lines) {
		const idx = line.indexOf(':')
		if (idx > -1) {
			const k = line.slice(0, idx).trim()
			const v = line.slice(idx + 1).trim()
			if (k) hdrs[k] = v
		}
	}
	return hdrs
}

const formatHeadersObject = (obj) => {
	return Object.entries(obj).map(([k, v]) => `${k}: ${v}`).join('\n')
}

const formattedResponseHeaders = computed(() => formatHeadersObject(responseHeaders.value))

const isJsonResponse = computed(() => {
	const ct = (responseHeaders.value['content-type'] || responseHeaders.value['Content-Type'] || '').toLowerCase()
	return ct.includes('application/json') || ct.includes('+json')
})

const prettyJson = computed(() => {
	try {
		return JSON.stringify(JSON.parse(responseText.value), null, 2)
	} catch (e) {
		return responseText.value
	}
})

const requestPreview = computed(() => {
	const hb = parseHeadersText(headersText.value)
	return `${method.value} ${url.value}\n\nHeaders:\n${formatHeadersObject(hb)}\n\nBody:\n${bodyText.value}`
})

const copyResponse = async () => {
	if (!responseText.value) return
	const ok = await copyToClipboard(responseText.value)
}

const downloadResponse = () => {
	if (!responseText.value) return
	const ext = isJsonResponse.value ? 'json' : 'txt'
	downloadFile(responseText.value, `response.${ext}`, isJsonResponse.value ? 'application/json' : 'text/plain')
}

const clearAll = () => {
	url.value = ''
	headersText.value = ''
	bodyText.value = ''
	responseText.value = ''
	responseHeaders.value = {}
	responseStatus.value = ''
	responseSize.value = '0 B'
	elapsed.value = 0
	hasResponse.value = false
	errorMessage.value = ''
}

const loadSample = () => {
	method.value = 'POST'
	url.value = 'https://httpbin.org/post'
	headersText.value = 'Accept: application/json\nUser-Agent: toolstation-api-tester'
	bodyText.value = JSON.stringify({ name: '八八', message: '测试请求' }, null, 2)
	contentType.value = 'application/json'
}

const sendRequest = async () => {
	errorMessage.value = ''
	hasResponse.value = false

	sending.value = true
	responseText.value = ''
	responseHeaders.value = {}
	responseStatus.value = ''
	elapsed.value = 0

	const controller = new AbortController()
	const timeout = setTimeout(() => controller.abort(), Math.max(1000, timeoutSec.value * 1000))

	const hdrs = parseHeadersText(headersText.value)
	// 如果用户选择了 contentType 且未在 headers 中写明 Content-Type，则添加
	if (contentType.value && !Object.keys(hdrs).some(k => k.toLowerCase() === 'content-type')) {
		// 对于 multipart/form-data 让浏览器自动生成 boundary，不要手动写
		if (contentType.value !== 'multipart/form-data') hdrs['Content-Type'] = contentType.value
	}

	let body = null
	if (method.value !== 'GET' && method.value !== 'HEAD') {
		if (contentType.value === 'application/json') {
			try {
				// allow raw JSON or plain text
				body = bodyText.value ? JSON.stringify(JSON.parse(bodyText.value)) : ''
			} catch (e) {
				// not valid JSON, send raw
				body = bodyText.value
			}
		} else if (contentType.value === 'application/x-www-form-urlencoded') {
			body = bodyText.value
		} else if (contentType.value === 'multipart/form-data') {
			// build FormData from simple key=value lines or raw JSON
			const fd = new FormData()
			try {
				const obj = JSON.parse(bodyText.value)
				Object.keys(obj).forEach(k => fd.append(k, obj[k]))
				body = fd
			} catch (e) {
				// parse lines key=value
				const lines = bodyText.value.split(/\r?\n/).filter(Boolean)
				for (const line of lines) {
					const idx = line.indexOf('=')
					if (idx > -1) fd.append(line.slice(0, idx).trim(), line.slice(idx + 1).trim())
				}
				body = fd
			}
		} else {
			body = bodyText.value
		}
	}

	const opts = {
		method: method.value,
		headers: hdrs,
		signal: controller.signal,
		body: body
	}

	const t0 = performance.now()
	try {
		// Prepare a serializable body for the proxy. If body is FormData, convert entries to object.
		let forwardBody = null
		if (body instanceof FormData) {
			const obj = {}
			for (const pair of body.entries()) {
				obj[pair[0]] = pair[1]
			}
			forwardBody = obj
		} else {
			forwardBody = body
		}

		const proxyReq = {
			url: url.value,
			method: method.value,
			headers: hdrs,
			body: forwardBody,
			timeoutSec: timeoutSec.value
		}

		const resp = await fetch('/api/proxy', {
			method: 'POST',
			headers: { 'Content-Type': 'application/json' },
			body: JSON.stringify(proxyReq),
			signal: controller.signal
		})

		const t1 = performance.now()
		elapsed.value = Math.round(t1 - t0)

		if (!resp.ok) {
			const errBody = await resp.text()
			// proxy-level error
			errorMessage.value = `代理请求失败: ${resp.status} ${resp.statusText} ${errBody}`
			event && event // noop to satisfy linter-like safety
			return
		}

		const data = await resp.json()

		responseStatus.value = `${data.status} ${data.statusText || ''}`
		responseHeaders.value = data.headers || {}
		responseText.value = data.body || ''
		responseSize.value = `${new Blob([responseText.value]).size} B`
		hasResponse.value = true

	} catch (err) {
		if (err && err.name === 'AbortError') {
			errorMessage.value = '请求已超时或被取消'
		} else {
			errorMessage.value = '请求失败: ' + (err && err.message ? err.message : String(err))
		}
	} finally {
		clearTimeout(timeout)
		sending.value = false
	}
}

// SEO
useHead({
	title: 'API 测试 - 八八在线工具',
	meta: [
		{ name: 'description', content: '在线 API 测试工具，支持自定义请求头与请求体，查看响应状态、响应头与响应体' }
	]
})
</script>

<style scoped>
.input-field {
	border: 1px solid #e5e7eb; /* gray-200 */
	border-radius: 0.5rem;
	padding: 0.5rem 0.75rem;
}
.input-field:focus {
	outline: none;
	box-shadow: 0 0 0 3px rgba(59,130,246,0.2); /* blue-300 ring */
}
.textarea-field {
	width: 100%;
	border: 1px solid #e5e7eb;
	border-radius: 0.5rem;
	padding: 0.75rem;
	font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, 'Roboto Mono', 'Helvetica Neue', monospace;
	font-size: 0.875rem;
	background: #ffffff;
	resize: vertical;
}
.primary-button {
	background-color: #2563eb; /* blue-600 */
	color: white;
	padding: 0.5rem 1rem;
	border-radius: 0.375rem;
}
.primary-button:hover { background-color: #1e40af; }
.secondary-button {
	background: #ffffff;
	border: 1px solid #e5e7eb;
	padding: 0.5rem 0.75rem;
	border-radius: 0.375rem;
}
.secondary-button:hover { background: #f9fafb; }
</style>
